﻿namespace HutongGames.PlayMakerEditor
{
    using HutongGames.PlayMaker;
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using UnityEditor;
    using UnityEngine;

    internal class FsmEventManager
    {
        private List<FsmEvent> eventList = new List<FsmEvent>();
        private const int NameColumnWidth = 260;
        private string newEventName = "";
        private Vector2 scrollPosition;
        private FsmEvent selectedEvent;
        private bool sortByUsageCount;
        private readonly List<string> unusedEvents = new List<string>();
        private readonly Dictionary<string, int> usageCount = new Dictionary<string, int>();

        private void AddEvent(string eventName)
        {
            if (eventName.Replace(" ", "") == "")
            {
                EditorApplication.Beep();
                EditorUtility.DisplayDialog("Add Event", "Invalid Name!", "OK");
            }
            else
            {
                FsmEditor.Builder.AddEvent(eventName, true);
                this.Reset();
            }
        }

        private int CompareEventsByUseCount(FsmEvent event1, FsmEvent event2)
        {
            int num;
            int num2;
            if (event1 == null)
            {
                if (event2 == null)
                {
                    return 0;
                }
                return -1;
            }
            if (event2 == null)
            {
                return 1;
            }
            this.usageCount.TryGetValue(event1.Name, out num);
            this.usageCount.TryGetValue(event2.Name, out num2);
            int num3 = num2.CompareTo(num);
            if (num3 != 0)
            {
                return num3;
            }
            return string.Compare(event1.Name, event2.Name, StringComparison.CurrentCulture);
        }

        private static int CountEventUsage(Fsm fsm, FsmEvent fsmEvent)
        {
            if (fsmEvent == null)
            {
                return 0;
            }
            return FsmInfo.FindStatesUsingEvent(fsm, fsmEvent.Name).Count;
        }

        private void DeleteUnusedEvents()
        {
            this.UpdateUseCount();
            int count = this.unusedEvents.Count;
            if (count == 0)
            {
                EditorUtility.DisplayDialog("Delete Unused Events", "No unused events...", "OK");
            }
            else
            {
                if (EditorUtility.DisplayDialog("Delete Unused Events", "Are you sure you want to delete " + count + " unused events?", "Yes", "No"))
                {
                    FsmEditor.RegisterUndo("Delete Unused Events");
                    foreach (string str in this.unusedEvents)
                    {
                        if (!FsmEvent.IsEventGlobal(str))
                        {
                            FsmEditor.Builder.DeleteEvent(FsmEditor.SelectedFsm, str);
                        }
                    }
                    this.Reset();
                }
                FsmEditor.SetFsmDirty(true, false);
            }
        }

        public void DeselectAll()
        {
            FsmEditor.ResetKeyboard();
            this.selectedEvent = null;
            this.newEventName = "";
            FsmEditor.Repaint(true);
        }

        private void DoEventEditor()
        {
            if (EditorWindow.focusedWindow == FsmEditor.Window)
            {
                EditorGUIUtility.LookLikeControls(86f);
                bool editingEvent = !FsmEvent.IsNullOrEmpty(this.selectedEvent);
                FsmEditorGUILayout.Divider(new GUILayoutOption[0]);
                if (editingEvent)
                {
                    if (!this.selectedEvent.IsSystemEvent)
                    {
                        if (FsmEditorSettings.ShowHints)
                        {
                            GUILayout.Box("NOTE: Use the Event Browser to rename Events across the project. Edit the name below to affect only this FSM.", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
                        }
                    }
                    else if (FsmEditorSettings.ShowHints)
                    {
                        GUILayout.Box("NOTE: System Events cannot be renamed!", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
                    }
                }
                if (!editingEvent || !this.selectedEvent.IsSystemEvent)
                {
                    EditorGUILayout.BeginHorizontal(new GUILayoutOption[0]);
                    GUILayout.Space(6f);
                    GUILayout.Label(editingEvent ? new GUIContent("Event Name", "Edit the selected Event. NOTE: This only renames the event in this FSM. Use the Event Browser to rename events across the project.") : new GUIContent("Add Event", "Add an Event to this FSM. Use the Browse button or Event Browser to quickly add existing events."), new GUILayoutOption[] { GUILayout.MaxWidth(80f) });
                    this.newEventName = EditorGUILayout.TextField(this.newEventName, new GUILayoutOption[0]);
                    string eventName = FsmEditorGUILayout.FsmEventListPopup();
                    if (eventName != "")
                    {
                        this.AddEvent(eventName);
                        return;
                    }
                    EditorGUILayout.EndHorizontal();
                    if (FsmEditorSettings.ShowHints && !editingEvent)
                    {
                        GUILayout.Box("Add an Event to this FSM. Use the Browse button or Event Browser to quickly add existing events.", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
                    }
                }
                if (editingEvent)
                {
                    bool flag2 = false;
                    foreach (FsmEvent event2 in FsmEditor.SelectedFsm.ExposedEvents)
                    {
                        if (event2.Name == this.selectedEvent.Name)
                        {
                            flag2 = true;
                            break;
                        }
                    }
                    bool flag3 = EditorGUILayout.Toggle(new GUIContent("Inspector", "Check to expose this event in the Inspector as an event button."), flag2, new GUILayoutOption[0]);
                    if (flag2 != flag3)
                    {
                        if (!flag3)
                        {
                            FsmBuilder.RemoveExposedEvent(FsmEditor.SelectedFsm, this.selectedEvent);
                        }
                        else
                        {
                            FsmEditor.SelectedFsm.ExposedEvents.Add(this.selectedEvent);
                        }
                        FsmEditor.SetFsmDirty(false, false);
                    }
                    if (FsmEditorSettings.ShowHints)
                    {
                        GUILayout.Box("Expose Events and Variables in the PlayMaker FSM Inspector to build a custom control panel for an FSM.", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
                    }
                }
                string str2 = this.ValidateEventName(editingEvent);
                bool flag4 = string.IsNullOrEmpty(str2);
                if (!flag4)
                {
                    GUILayout.Box(str2, FsmEditorStyles.ErrorBox, new GUILayoutOption[0]);
                }
                if (Event.current.isKey)
                {
                    if (flag4 && FsmEditorUtility.EnterKeyPressed())
                    {
                        if (!editingEvent)
                        {
                            this.AddEvent(this.newEventName);
                        }
                        else
                        {
                            this.RenameEvent(this.selectedEvent, this.newEventName);
                        }
                        Event.current.Use();
                        GUIUtility.ExitGUI();
                    }
                    else if (Event.current.keyCode == KeyCode.Escape)
                    {
                        this.Reset();
                    }
                }
            }
        }

        private void DoEventLine(FsmEvent fsmEvent)
        {
            int num;
            this.usageCount.TryGetValue(fsmEvent.Name, out num);
            GUILayout.BeginHorizontal(((this.selectedEvent != null) && (fsmEvent.Name == this.selectedEvent.Name)) ? FsmEditorStyles.SelectedEventBox : FsmEditorStyles.TableRowBox, new GUILayoutOption[0]);
            bool enabled = GUI.enabled;
            if (fsmEvent.IsSystemEvent)
            {
                GUI.enabled = false;
            }
            bool isGlobal = GUILayout.Toggle(fsmEvent.IsGlobal, new GUIContent("", "Global"), FsmEditorStyles.TableRowCheckBox, new GUILayoutOption[] { GUILayout.MaxWidth(17f), GUILayout.MinWidth(17f) });
            if (isGlobal != fsmEvent.IsGlobal)
            {
                FsmEditor.Builder.SetEventIsGlobal(fsmEvent, isGlobal);
            }
            GUI.enabled = enabled;
            GUIStyle style = ((this.selectedEvent != null) && (fsmEvent.Name == this.selectedEvent.Name)) ? FsmEditorStyles.TableRowTextSelected : FsmEditorStyles.TableRowText;
            if (GUILayout.Button(fsmEvent.Name, style, new GUILayoutOption[] { GUILayout.MinWidth(260f) }))
            {
                this.SelectEvent(fsmEvent, true);
                GUIUtility.keyboardControl = 0;
                if ((Event.current.button == 1) || EditorGUI.actionKey)
                {
                    this.GenerateStateListMenu(this.selectedEvent).ShowAsContext();
                }
            }
            GUILayout.FlexibleSpace();
            GUILayout.Label(num.ToString(CultureInfo.CurrentCulture), style, new GUILayoutOption[0]);
            GUILayout.Space(10f);
            if (FsmEditorGUILayout.DeleteButton())
            {
                FsmEditor.Builder.DeleteEvent(fsmEvent);
                this.Reset();
            }
            GUILayout.EndHorizontal();
        }

        private void DoEventTable()
        {
            this.scrollPosition = GUILayout.BeginScrollView(this.scrollPosition, new GUILayoutOption[0]);
            if (this.eventList.Count == 0)
            {
                GUILayout.BeginHorizontal(FsmEditorStyles.TableRowBox, new GUILayoutOption[0]);
                GUILayout.Label("[none]", new GUILayoutOption[0]);
                GUILayout.EndHorizontal();
            }
            foreach (FsmEvent event2 in this.eventList)
            {
                this.DoEventLine(event2);
            }
            GUILayout.Space(20f);
            GUILayout.EndScrollView();
            GUILayout.FlexibleSpace();
        }

        private void DoTableHeaders()
        {
            EditorGUILayout.BeginHorizontal(new GUILayoutOption[0]);
            bool changed = GUI.changed;
            GUI.changed = false;
            GUILayout.BeginHorizontal(FsmEditorStyles.TableRowBox, new GUILayoutOption[0]);
            GUILayout.Toggle(false, new GUIContent(FsmEditorStyles.BroadcastIcon, "Global flag. Global events can be sent between FSMs."), FsmEditorStyles.TableRowHeader, new GUILayoutOption[0]);
            this.sortByUsageCount = !GUILayout.Toggle(!this.sortByUsageCount, new GUIContent("Event", "Right-click an Event to select States that use the Event."), FsmEditorStyles.TableRowHeader, new GUILayoutOption[] { GUILayout.MinWidth(260f) });
            this.sortByUsageCount = GUILayout.Toggle(this.sortByUsageCount, new GUIContent("Used", "Number of States that use the Event."), FsmEditorStyles.TableRowHeader, new GUILayoutOption[0]);
            GUILayout.FlexibleSpace();
            if (FsmEditorGUILayout.SettingsButtonPadded())
            {
                this.GenerateEventManagerMenu().ShowAsContext();
            }
            GUILayout.EndHorizontal();
            if (GUI.changed)
            {
                this.SortEvents();
            }
            else
            {
                GUI.changed = changed;
            }
            EditorGUILayout.EndHorizontal();
            if (FsmEditorSettings.ShowHints)
            {
                GUILayout.Box("Right-click an Event to select States that use the Event.", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
            }
        }

        private GenericMenu GenerateEventManagerMenu()
        {
            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("Remove Unused Events"), false, new GenericMenu.MenuFunction(this.DeleteUnusedEvents));
            menu.AddSeparator("");
            menu.AddItem(new GUIContent("Event Browser"), false, new GenericMenu.MenuFunction(FsmEditor.OpenGlobalEventsWindow));
            menu.AddSeparator("");
            menu.AddItem(new GUIContent("Online Help"), false, new GenericMenu.MenuFunction(FsmEventManager.OpenOnlineHelp));
            return menu;
        }

        private GenericMenu GenerateStateListMenu(FsmEvent fsmEvent)
        {
            int num;
            this.UpdateUseCount();
            GenericMenu menu = new GenericMenu();
            this.usageCount.TryGetValue(fsmEvent.Name, out num);
            if (num == 0)
            {
                menu.AddDisabledItem(new GUIContent("No states use this event..."));
                return menu;
            }
            foreach (FsmState state in FsmInfo.FindStatesUsingEvent(FsmEditor.SelectedFsm, fsmEvent.Name))
            {
                menu.AddItem(new GUIContent(state.Name), FsmEditor.SelectedState == state, new GenericMenu.MenuFunction2(EditorCommands.SelectState), state);
            }
            return menu;
        }

        public void OnGUI()
        {
            if (FsmEditor.SelectedFsm == null)
            {
                GUILayout.FlexibleSpace();
            }
            else
            {
                this.DoTableHeaders();
                this.DoEventTable();
                if (Event.current.type == EventType.ContextClick)
                {
                    this.GenerateEventManagerMenu().ShowAsContext();
                }
                this.DoEventEditor();
                EditorGUILayout.Space();
                if (GUILayout.Button(new GUIContent("Event Browser", "Use the Event Browser to manage Events across your Project."), new GUILayoutOption[0]))
                {
                    FsmEditor.OpenGlobalEventsWindow();
                    GUIUtility.ExitGUI();
                }
                if (FsmEditorSettings.ShowHints)
                {
                    GUILayout.Box("Use the Event Browser to manage Events in your Project.", FsmEditorStyles.HintBox, new GUILayoutOption[0]);
                }
                EditorGUILayout.Space();
                if ((Event.current.type == EventType.MouseDown) && (GUIUtility.keyboardControl == 0))
                {
                    this.Reset();
                }
            }
        }

        private static void OpenOnlineHelp()
        {
            EditorCommands.OpenWikiPage(WikiPages.EventManager);
        }

        private void RenameEvent(FsmEvent fsmEvent, string newName)
        {
            if (fsmEvent != null)
            {
                if (fsmEvent.IsGlobal)
                {
                    if (EditorUtility.DisplayDialog("Rename Event", "This is a Global Event, it will be renamed globally...", "OK", "Cancel"))
                    {
                        FsmEditor.Builder.RenameEvent(fsmEvent.Name, newName);
                    }
                }
                else
                {
                    FsmEditor.Builder.RenameEvent(FsmEditor.SelectedFsm, fsmEvent.Name, newName);
                }
                this.Reset();
            }
        }

        public void Reset()
        {
            this.DeselectAll();
            this.UpdateEventList();
            this.UpdateUseCount();
            FsmEditor.Repaint(true);
            FsmEditor.RepaintAll();
            GlobalEventsWindow.ResetView();
        }

        public void SelectEvent(FsmEvent fsmEvent, [Optional, DefaultParameterValue(true)] bool syncSelection)
        {
            if (syncSelection)
            {
                GlobalEventsWindow.SyncSelection(fsmEvent);
            }
            this.selectedEvent = fsmEvent;
            if (FsmEvent.IsNullOrEmpty(fsmEvent))
            {
                this.newEventName = "";
            }
            else
            {
                this.newEventName = !fsmEvent.IsSystemEvent ? fsmEvent.Name : "";
                FsmEditor.Repaint(true);
            }
        }

        private void SortEvents()
        {
            if (this.sortByUsageCount)
            {
                this.eventList.Sort(new Comparison<FsmEvent>(this.CompareEventsByUseCount));
            }
            else
            {
                this.eventList.Sort();
            }
        }

        private void UpdateEventList()
        {
            foreach (Fsm fsm in FsmEditor.FsmList)
            {
                FsmEditorUtility.SanityCheckEventList(fsm);
            }
            if (FsmEditor.SelectedFsm != null)
            {
                this.eventList = new List<FsmEvent>(FsmEditor.SelectedFsm.Events);
                this.SortEvents();
            }
            else
            {
                this.eventList = new List<FsmEvent>();
            }
        }

        public void UpdateUseCount()
        {
            this.usageCount.Clear();
            this.unusedEvents.Clear();
            if (FsmEditor.SelectedFsm != null)
            {
                foreach (FsmEvent event2 in FsmEditor.SelectedFsm.Events)
                {
                    int num = CountEventUsage(FsmEditor.SelectedFsm, event2);
                    this.usageCount.Add(event2.Name, num);
                    if (num == 0)
                    {
                        this.unusedEvents.Add(event2.Name);
                    }
                }
            }
        }

        private string ValidateEventName(bool editingEvent)
        {
            if (editingEvent && this.selectedEvent.IsSystemEvent)
            {
                return null;
            }
            if (!editingEvent)
            {
                return FsmEditor.Builder.ValidateAddEvent(this.newEventName);
            }
            return FsmEditor.Builder.ValidateRenameEvent(this.selectedEvent, this.newEventName);
        }
    }
}

